import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.sun.org.apache.xerces.internal.impl.xpath.regex.ParseException;

import Shapes.Node;

import processing.core.*;


public class TimeView extends PApplet {

	// those parameters are for animation of nodes
	// Controls cubie's rotation
	Node stage; // external large cube
	int cubies = 20;
	// Size of external cube
	float bounds = 300;
	Node[] c = new Node[cubies]; // internal little cubes
	int[][] quadBG = new int[cubies][6];

	// Controls cubie's movement
	float[] x = new float[cubies];
	float[] y = new float[cubies];
	float[] z = new float[cubies];
	float[] xSpeed = new float[cubies];
	float[] ySpeed = new float[cubies];
	float[] zSpeed = new float[cubies];

	float[] xRot = new float[cubies];
	float[] yRot = new float[cubies];
	float[] zRot = new float[cubies];

	// those parameters are for timeline

	int dateSelectorX;
	int dateSelectorY = 100;
	int dateCount = 250;
	// Don't show the first 10 days, they're too erratic.
	int minDateIndex = 0;
	// The last day of the season, or yesterday, if the season is ongoing.
	// This is the maximum date that can be viewed.
	int maxDateIndex = 50;

	// The number of days in the entire season.
	// int dateCount;
	// The current date being shown.
	int dateIndex;

	// This format makes "20070704" from the date July 4, 2007.
	DateFormat stampFormat = new SimpleDateFormat("yyyyMMdd");
	// This format makes "4 July 2007" from the same.
	DateFormat prettyFormat = new SimpleDateFormat("d MMMM yyyy");

	// All dates for the season formatted with stampFormat.
	String[] dateStamp;
	// All dates in the season formatted with prettyFormat.
	String[] datePretty;

	// --------------------------here is to setup everything
	// ---------------------//   

	

	

	public void setup() {
		size(800, 600, P3D);
		background(0);
		setupNode();
		try {
			setupDates();
		} catch (java.text.ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 
	 */
	public void setupNode() {
		for (int i = 0; i < cubies; i++) {
			// Each cube face has a random color component
			float colorShift = random(-75, 75);
			quadBG[i][0] = color(0);
			quadBG[i][1] = color(51);
			quadBG[i][2] = color(102);
			quadBG[i][3] = color(153);
			quadBG[i][4] = color(204);
			quadBG[i][5] = color(255);

			// Cubies are randomly sized
			float cubieSize = random(5, 15);

			c[i] = new Node(this);
		

			// Initialize cubie's position, speed and rotation
			x[i] = 0;
			y[i] = 0;
			z[i] = 0;
			
	//		c[i].setup("hello", x[i], y[i], z[i]);

			xSpeed[i] = random(-1, 1);
			ySpeed[i] = random(-1, 1);
			zSpeed[i] = random(-1, 1);

			xRot[i] = random(40, 100);
			yRot[i] = random(40, 100);
			zRot[i] = random(40, 100);
		}
	}

	// ------------------copied from
	// example------------------------------------------//

	String firstDateStamp = "19970101";
	String lastDateStamp = "20091231";
	String todayDateStamp;

	static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000 * 20;

	void setupDates() throws java.text.ParseException {
		try {
			Date firstDate = stampFormat.parse(firstDateStamp);
			long firstDateMillis = firstDate.getTime();

			Date lastDate = stampFormat.parse(lastDateStamp);
			long lastDateMillis = lastDate.getTime();

			// Calculate number of days by dividing the total milliseconds
			// between the first and last dates by the number of milliseconds
			// per day
			dateCount = (int) ((lastDateMillis - firstDateMillis) / MILLIS_PER_DAY) + 1;
			maxDateIndex = dateCount;
			dateStamp = new String[dateCount];
			datePretty = new String[dateCount];

			todayDateStamp = year() + nf(month(), 2) + nf(day(), 2);
			// Another option to do this, but more code
			// Date today = new Date();
			// String todayDateStamp = stampFormat.format(today);

			for (int i = 0; i < dateCount; i++) {
				Date date = new Date(firstDateMillis + MILLIS_PER_DAY * i);
				datePretty[i] = prettyFormat.format(date);
				dateStamp[i] = stampFormat.format(date);
				// If this value for 'date' is equal to today, then set the
				// previous
				// day as the maximum viewable date, because it means the season
				// is
				// still ongoing. The previous day is used because unless it is
				// late
				// in the evening, the updated numbers for the day will be
				// unavailable
				// or incomplete.
				if (dateStamp[i].equals(todayDateStamp)) {
					maxDateIndex = i - 1;
				}
			}
		} catch (ParseException e) {
			die("Problem while setting up dates", e);
		}
	}
	
	
	
	public void setupBubbles(){
		for (int i = 0; i < 12; i++) {
			// Each cube face has a random color component


			// Initialize cubie's position, speed and rotation
			x[i] = 0;
			y[i] = 0;
			z[i] = 0;

			xSpeed[i] = random(-1, 1);
			ySpeed[i] = random(-1, 1);
			zSpeed[i] = random(-1, 1);

			xRot[i] = random(40, 100);
			yRot[i] = random(40, 100);
			zRot[i] = random(40, 100);
		}
	}

	// -------------------from here is the draw method --------------//

	public void draw() {

		background(0);

		lights();
		translate(width / 2, height / 2, -130);
		// this is for test
		stroke(255);
//		if (mousePressed) {
	//		line(mouseX, mouseY, pmouseX, pmouseY);
	//	}

	//	this.drawNode();

		this.drawTimeline();
		//

	}

	// ------here we draw the time line ----------------//
	// -------------------------------------------we draw a timeline
	// --------------//

	// Draw a series of lines for selecting the date
	public void drawTimeline() {
		// dateSelectorX = (width - dateCount*2) / 2;
		dateSelectorX = -width / 3;
		strokeWeight(1);
		for (int i = 0; i < dateCount; i++) {
			int x = dateSelectorX + i * 2;

			// If this is the currently selected date, draw it differently
			if (i == dateIndex) {
				// if(false){
				stroke(0);
				line(x, -280, 150, x, -250, 150);
				textAlign(CENTER, TOP);
				text(datePretty[dateIndex], x, -240, 150);

			} else {
				// If this is a viewable date, make the line darker
				if ((i >= minDateIndex) && (i <= maxDateIndex)) {
					stroke(128); // Viewable date
				} else {
					stroke(204); // Not a viewable date
				}
				line(x, -280, 150, x, -260, 150);
			}
		}
	}

	// draw some bubbles here to text whether we can change the size
	public void drawBubbles() {
		noStroke();
		translate(5, 300, 150);
		sphere(40);

	}

	// this is for strings
	// -------------------------------------------------------------//

	// ..---------------------------------------------//

	// now this is interactive operations ----- for mouse ----//

	public void mousePressed() {
		handleMouse();
	}

	public void mouseDragged() {
		handleMouse();
	}

	void handleMouse() {
		if (mouseY < dateSelectorY) {
			int date = (mouseX - width / 2 - dateSelectorX) / 2;
			setDate(constrain(date, minDateIndex, maxDateIndex));
		}
	}

	void setDate(int index) {
		dateIndex = index;
		// standings = season[dateIndex];

		// for (int i = 0; i < teamCount; i++) {
		// standingsPosition[i].target(standings.getRank(i));
		// }
		// Re-enable the animation loop
		loop();
	}

	public void drawTrees() {

	}

	public void drawNode() {

		// Move and rotate cubies
		for (int i = 0; i < cubies; i++) {
			pushMatrix();
			translate(x[i], y[i], z[i]);
		//	rotateX(frameCount * PI / xRot[i]);
		//	rotateY(frameCount * PI / yRot[i]);
		//	rotateX(frameCount * PI / zRot[i]);
			noStroke();
			c[i].draw();
			x[i] += xSpeed[i];
			y[i] += ySpeed[i];
			z[i] += zSpeed[i];
			popMatrix();

			// Draw lines connecting cubbies
			stroke(255);
			if (i < cubies - 1) {
				line(x[i], y[i], z[i], x[i + 1], y[i + 1], z[i + 1]);
			}

			// Check wall collisions
			if (x[i] > bounds / 2 || x[i] < -bounds / 2) {
				xSpeed[i] *= -1;
			}
			if (y[i] > bounds / 2 || y[i] < -bounds / 2) {
				ySpeed[i] *= -1;
			}
			if (z[i] > bounds / 2 || z[i] < -bounds / 2) {
				zSpeed[i] *= -1;
			}
		}

	}
	
	
	public void drawSpring(){
		
	}

	public void drawLine() {

	}
}